package com.zzyl.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.ResourceCacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 查询资源列表
     *
     * @param dto
     * @return
     */
//    @Override
//    public List<ResourceVo> findResourceList(ResourceDto dto) {
////        访问redis，获取数据
//        String jsonStr = redisTemplate.opsForValue().get("resourceList");
//        log.info("jsonStr={}",jsonStr);
//        if (StringUtils.isNotBlank(jsonStr)){
//            log.info("缓存中有数据，返回");
//            List<ResourceVo> voList = JSONUtil.toList(jsonStr, ResourceVo.class);
////            如果有条件，就在集合中进行遍历找到符合条件的数据
////            List<ResourceVo> resultList = new ArrayList<>();
////            for (ResourceVo vo : voList) {
////                if (StringUtils.isNotBlank(dto.getParentResourceNo())
////                        && dto.getParentResourceNo().equals(vo.getParentResourceNo())
////                        && StringUtils.isNotBlank(dto.getResourceType())
////                        && dto.getResourceType().equals(vo.getResourceType())){
////                    resultList.add(vo);
////                }
////            }
////            使用lambda表达式实现
//            List<ResourceVo> resultList = voList;
//            if (dto != null
//                        && StringUtils.isNotBlank(dto.getParentResourceNo())
//                        && StringUtils.isNotBlank(dto.getResourceType())){
//                resultList = voList.stream()
//                        .filter(vo -> vo.getParentResourceNo().equals(dto.getParentResourceNo()))
//                        .filter(vo -> vo.getResourceType().equals(dto.getResourceType()))
//                        .collect(Collectors.toList());
//            }
////            如果有数据，就直接返回
//            return resultList;
//        } else {
//            log.info("缓存中没有数据，查询数据库");
////        如果没有数据，查询数据库
////        把数据库的结果，放入redis中
//            List<ResourceVo> voList = resourceMapper.selectByCondition(dto);
//            redisTemplate.opsForValue().set("resourceList",JSONUtil.toJsonStr(voList));
//            return voList;
//        }
//    }
    @Cacheable(cacheNames = ResourceCacheConstant.PREFIX + ResourceCacheConstant.RESOURCES_LIST,
            key = "#dto.hashCode()")
    @Override
    public List<ResourceVo> findResourceList(ResourceDto dto) {
        log.info("缓存中有数据，返回");
//        如果没有数据，查询数据库
//        把数据库的结果，放入redis中
        List<ResourceVo> voList = resourceMapper.selectByCondition(dto);
        return voList;
    }

    /**
     * 资源的树形结构
     *
     * @param itemVo
     * @return
     */
//    @Override
//    public TreeVo findResourceTree(TreeItemVo itemVo) {
////        查询缓存，如果存在，直接返回
//        String jsonStr = redisTemplate.opsForValue().get("resourceTree");
//        if (StringUtils.isNotBlank(jsonStr)) {
//            log.info("缓存中有数据，返回");
//            TreeVo vo = JSONUtil.toBean(jsonStr, TreeVo.class);
////            如果有数据，就直接返回
//            return vo;
//        } else {
//            log.info("缓存中没有数据，查询数据库");
////        如果不存在，查询数据库，放入redis中
////        创建根菜单
//            TreeItemVo rootItem = new TreeItemVo(SuperConstant.ROOT_PARENT_ID, "智慧养老院", new ArrayList<TreeItemVo>());
//            ResourceDto resourceDto = new ResourceDto();
//            resourceDto.setResourceType("m");
////        从数据库中查询菜单，不要在循环中查询数据，一次性把数据都查询回来，在java的内存中处理树的关系
//            List<ResourceVo> voList = resourceMapper.selectByCondition(resourceDto);
////        使用递归进行树结构
//            createTree(voList, rootItem);
//            ArrayList<TreeItemVo> list = new ArrayList<>();
//            list.add(rootItem);
//            TreeVo vo = new TreeVo(list);
//            redisTemplate.opsForValue().set("resourceTree", JSONUtil.toJsonStr(vo));
//            return vo;
//        }
//    }
    @Cacheable(cacheNames = ResourceCacheConstant.PREFIX + ResourceCacheConstant.RESOURCE_TREE)
    @Override
    public TreeVo findResourceTree(TreeItemVo itemVo) {
//        查询缓存，如果存在，直接返回
        log.info("缓存中有数据，返回");
//        如果不存在，查询数据库，放入redis中
//        创建根菜单
        TreeItemVo rootItem = new TreeItemVo(SuperConstant.ROOT_PARENT_ID, "智慧养老院", new ArrayList<TreeItemVo>());
        ResourceDto resourceDto = new ResourceDto();
        resourceDto.setResourceType("m");
//        从数据库中查询菜单，不要在循环中查询数据，一次性把数据都查询回来，在java的内存中处理树的关系
        List<ResourceVo> voList = resourceMapper.selectByCondition(resourceDto);
//        使用递归进行树结构
        createTree(voList, rootItem);
        ArrayList<TreeItemVo> list = new ArrayList<>();
        list.add(rootItem);
        TreeVo vo = new TreeVo(list);
        redisTemplate.opsForValue().set("resourceTree", JSONUtil.toJsonStr(vo));
        return vo;
    }

    /**
     * 添加资源
     *
     * @param resource
     * @return
     */
    @Override
    public void addResource(Resource resource) {
//        查询父级数据
        Resource parent = resourceMapper.selectByNo(resource.getParentResourceNo());
//        判断状态是否与父级一致
        if (!resource.getDataState().equals(parent.getDataState())) {
//            与父级状态不一致，抛异常
            throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
        }
//        生成编号
//        根据父级编号 查询 子菜单集合 根据编号倒叙排序
        List<Resource> resourceList = resourceMapper.selectResourceByParentNo(resource.getParentResourceNo());
        String no = "";
        if (CollectionUtil.isEmpty(resourceList)) {
//              如果没有子菜单，直接生成
            no = NoProcessing.createNo(resource.getParentResourceNo(), false);
        } else {
//              如果有子菜单，在最大编号的基础上进行追加
            no = NoProcessing.createNo(resourceList.get(0).getResourceNo(), true);
        }
        if (resource.getResourceType().equals("m") &&
                !no.endsWith("000")) {
//            如果是菜单，最后的3位应该都是0
            throw new BaseException(BasicEnum.BAD_MENU_NO);
        }
        log.info("no={}", no);
//        保存
        resource.setResourceNo(no);
        resourceMapper.insert(resource);
    }

    @Override
    public List<MenuVo> menus() {
//        获取当前用户
        Long userId = UserThreadLocal.getMgtUserId();
        log.info("userId={}",userId);
//        查询用户的菜单信息 type=m datastate=0 userid=xxx
        List<MenuVo> menuVoList = resourceMapper.selectResourceMenuByUserId(userId);
//        log.info("菜单集合={}",menuVoList);
//        处理菜单之间的父子关系
//        获取到 所有的父菜单以及它的子菜单集合  Map<parentNo,List<MenuVo>>
//        Map<String,List<MenuVo>> map = new HashMap<>();
//        for (MenuVo menuVo : menuVoList) {
//            String resourceNo = menuVo.getResourceNo();
//            for (MenuVo vo : menuVoList) {
//                if (vo.getParentResourceNo().equals(resourceNo)){
//                    if (map.get(resourceNo) != null && map.get(resourceNo).size() > 0){
//                       map.get(resourceNo).add(vo);
//                    } else {
//                        List<MenuVo> list = new ArrayList<>();
//                        list.add(vo);
//                        map.put(resourceNo,list);
//                    }
//                }
//            }
//        }
        Map<String, List<MenuVo>> parentMap = menuVoList.stream()
                .collect(Collectors.groupingBy(MenuVo::getParentResourceNo));
//        log.info("map={}",parentMap);
        for (MenuVo menuVo : menuVoList) {
            menuVo.setRedirect("/" + menuVo.getName());
            menuVo.setMeta(new MenuMetaVo(menuVo.getName(),null,null));
            String resourceNo = menuVo.getResourceNo();
            List<MenuVo> childrenList = parentMap.get(resourceNo);
            if (!CollectionUtils.isEmpty(childrenList)){
                for (MenuVo vo : childrenList) {
                    vo.setRedirect(menuVo.getRedirect() + "/" + vo.getName());
                    vo.setMeta(new MenuMetaVo(vo.getName(),null,null));
                }
                menuVo.setChildren(childrenList);
            }
        }
        List<MenuVo> voList = parentMap.get(SuperConstant.ROOT_PARENT_ID);
        log.info("voList={}",voList);
        return voList;
    }

    @Override
    public List<String> findButResourceByUserId(Long userId) {
        return resourceMapper.selectButResourceByUserId(userId);
    }

    @Override
    public List<String> findAllButResource() {
        return resourceMapper.selectAllButResource();
    }

    /**
     * 使用递归处理voList 构建Tree的结构
     *
     * @param voList
     * @param rootItem
     */
    private void createTree(List<ResourceVo> voList, TreeItemVo rootItem) {
        for (ResourceVo vo : voList) {
            if (vo.getParentResourceNo().equals(rootItem.getId())
                    && vo.getResourceNo().endsWith("000")) {
//                创建当前的孩子节点
                TreeItemVo itemVo = new TreeItemVo(vo.getResourceNo(), vo.getResourceName(), new ArrayList<>());
//                把孩子节点，放入父节点的孩子集合中
                rootItem.getChildren().add(itemVo);
//                用当前的孩子节点，作为夫节点，查询它的孩子节点
                createTree(voList, itemVo);
            }
        }
        log.info("rootItem={}", rootItem);
    }
}
